home *** CD-ROM | disk | FTP | other *** search
Text File | 2002-06-17 | 37.7 KB | 1,747 lines |
- // Copyright (C) 2001-2002 Raven Software.
- //
- // BG_Player.c
-
- #include "q_shared.h"
- #include "bg_public.h"
- #include "bg_local.h"
-
- #include "..\ghoul2\g2.h"
-
- #include "../cgame/animtable.h"
-
- #ifdef QAGAME
- #include "g_local.h"
- #endif
-
- #ifdef UI_EXPORTS
- #include "../ui/ui_local.h"
- #endif
-
- #ifndef UI_EXPORTS
- #ifndef QAGAME
- #include "../cgame/cg_local.h"
- #endif
- #endif
-
- TCharacterTemplate *bg_characterTemplates = NULL;
- TItemTemplate *bg_itemTemplates = NULL;
- int bg_identityCount = 0;
- TIdentity bg_identities[MAX_IDENTITIES];
-
- goutfitting_t bg_outfittings[MAX_OUTFITTINGS];
- int bg_outfittingCount = 0;
-
- char bg_availableOutfitting[WP_NUM_WEAPONS] = {-1};
-
- int bg_outfittingGroups[OUTFITTING_GROUP_MAX][MAX_OUTFITTING_GROUPITEM] =
- {
- { MODELINDEX_WEAPON_AK74, MODELINDEX_WEAPON_M4, MODELINDEX_WEAPON_USAS12, MODELINDEX_WEAPON_MSG90A1, MODELINDEX_WEAPON_M60, MODELINDEX_WEAPON_MP5, MODELINDEX_WEAPON_RPG7, MODELINDEX_WEAPON_MM1, -1, -1 },
- { MODELINDEX_WEAPON_M590, MODELINDEX_WEAPON_MICROUZI, MODELINDEX_WEAPON_M3A1, -1, -1, -1, -1, -1, -1, - 1 },
- { MODELINDEX_WEAPON_M19, MODELINDEX_WEAPON_SOCOM, -1, -1, -1, -1, -1, -1, -1, -1 },
- { MODELINDEX_WEAPON_SMOHG92, MODELINDEX_WEAPON_M84, MODELINDEX_WEAPON_M15, MODELINDEX_WEAPON_ANM14, -1, -1, -1, -1, -1, -1 },
- { MODELINDEX_ARMOR, MODELINDEX_NIGHTVISION, MODELINDEX_THERMAL, -1, -1, -1, -1, -1, -1, -1 },
- };
-
- /*
- ===================
- PM_StartLegsAnim
-
- Starts a new leg animation for the given playerstate
- ===================
- */
- static void PM_StartLegsAnim( playerState_t* ps, int anim )
- {
- if ( ps->pm_type >= PM_DEAD )
- {
- return;
- }
-
- ps->legsAnim = ( ( ps->legsAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim;
- }
-
- /*
- ===================
- PM_ContinueLegsAnim
-
- Continues running the given leg animation, if its a new animation then it is started
- ===================
- */
- void PM_ContinueLegsAnim( playerState_t* ps, int anim )
- {
- if ( ( ps->legsAnim & ~ANIM_TOGGLEBIT ) == anim )
- {
- return;
- }
-
- PM_StartLegsAnim( ps, anim );
- }
-
- /*
- ===================
- PM_ForceLegsAnim
- ===================
- */
- void PM_ForceLegsAnim( playerState_t* ps, int anim)
- {
- PM_StartLegsAnim( ps, anim );
- }
-
- /*
- ===================
- PM_StartTorsoAnim
- ===================
- */
- void PM_StartTorsoAnim( playerState_t* ps, int anim, int time )
- {
- if ( anim == -1 )
- {
- return;
- }
-
- if ( ps->pm_type >= PM_DEAD )
- {
- return;
- }
-
- ps->torsoAnim = ( ( ps->torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim;
- ps->torsoTimer = time;
- }
-
- /*
- ===================
- PM_ContinueTorsoAnim
-
- Continues running the given torso animation, if its a new animation then it is started
- ===================
- */
- static void PM_ContinueTorsoAnim( playerState_t* ps, int anim )
- {
- if ( anim == -1 )
- {
- return;
- }
-
- if ( ( ps->torsoAnim & ~ANIM_TOGGLEBIT ) == anim )
- {
- return;
- }
-
- PM_StartTorsoAnim( ps, anim, 0 );
- }
-
- /*
- ==============
- PM_TorsoAnimation
-
- Sets the current torso animation based on the given playerstate
- ==============
- */
- void PM_TorsoAnimation( playerState_t* ps )
- {
- switch ( ps->weaponstate )
- {
- case WEAPON_SPAWNING:
- case WEAPON_READY:
-
- if ( ps->stats[STAT_USEWEAPONDROP] )
- {
- PM_ContinueTorsoAnim ( ps, TORSO_USE );
- }
- else if ( (ps->pm_flags & PMF_ZOOMED) && weaponData[ps->weapon].animIdleZoomed )
- {
- PM_ContinueTorsoAnim ( ps, weaponData[ps->weapon].animIdleZoomed );
- }
- else
- {
- PM_ContinueTorsoAnim ( ps, weaponData[ps->weapon].animIdle );
- }
-
- break;
- }
- }
-
- /*
- =================
- BG_ParseInventory
-
- Parses the inventory items indicated in the given group and returns
- a linked list containing the results
- =================
- */
- TInventoryTemplate *BG_ParseInventory ( TGPGroup group )
- {
- TInventoryTemplate *top, *inv;
- TGPGroup subGroup;
- char temp[1024];
-
- // Convienience for handling no items
- if (!group)
- {
- return 0;
- }
-
- top = NULL;
-
- // Parse each of the inventory items
- subGroup = trap_GPG_GetSubGroups( group );
- while(subGroup)
- {
- trap_GPG_GetName ( subGroup, temp );
-
- // If the group name isnt item then 'Item' then its not an inventory item
- if ( Q_stricmp ( temp, "Item") == 0)
- {
- inv = (TInventoryTemplate *)trap_VM_LocalAlloc ( sizeof(*inv));
-
- // Name of the item
- trap_GPG_FindPairValue ( subGroup, "Name||Name1", "", temp );
- inv->mName = trap_VM_LocalStringAlloc ( temp );
-
- // Bolt for the item
- trap_GPG_FindPairValue ( subGroup, "Bolt", "", temp );
- inv->mBolt = trap_VM_LocalStringAlloc ( temp );
-
- trap_GPG_FindPairValue ( subGroup, "mp_onback||onback", "no", temp );
- if ( !Q_stricmp ( temp, "yes" ) )
- {
- inv->mOnBack = qtrue;
- }
-
- inv->mNext = top;
- top = inv;
- }
-
- // Move to the next group
- subGroup = trap_GPG_GetNext ( subGroup );
- }
-
- return top;
- }
-
- /*
- =================
- BG_ParseSkins
-
- Parses the skins contained in the given group and returns a linked
- list with the results
- =================
- */
- TSkinTemplate *BG_ParseSkins( TCharacterTemplate* character, TGPGroup group )
- {
- TSkinTemplate *skin;
- TIdentity *identity;
- TGPGroup subGroup;
- char temp[1024];
- fileHandle_t f;
- #ifndef SPECIAL_PRE_CACHE
- int len;
- #endif
- qboolean validSkin;
-
- character->mSkins = NULL;
-
- // Parse the skin file first
- trap_GPG_FindPairValue ( group, "SkinFile", "", temp );
- if ( temp[0] )
- {
- skin = (TSkinTemplate *) trap_VM_LocalAlloc ( sizeof(*skin) );
-
- skin->mSkin = trap_VM_LocalStringAlloc ( temp );
- skin->mNext = character->mSkins;
- character->mSkins = skin;
- }
-
- // Now parse all the skin groups
- subGroup = trap_GPG_GetSubGroups ( group );
- while(subGroup)
- {
- trap_GPG_GetName ( subGroup, temp );
-
- // If the groups name isnt 'Skin' then skip it
- if ( Q_stricmp( temp, "Skin") == 0 )
- {
- // Allocate memory for the skin
- skin = (TSkinTemplate *) trap_VM_LocalAlloc ( sizeof(*skin) );
-
- // Grab the skin filename
- trap_GPG_FindPairValue ( subGroup, "File", "", temp );
- skin->mSkin = trap_VM_LocalStringAlloc ( temp );
-
- #ifdef SPECIAL_PRE_CACHE
- f = 0;
- validSkin = qtrue;
- #else
- Com_sprintf( temp, sizeof(temp), "models/characters/skins/%s.g2skin", skin->mSkin );
- len = trap_FS_FOpenFile( temp, &f, FS_READ );
- if (f != 0)
- {
- trap_FS_FCloseFile(f);
- validSkin = qtrue;
- }
- else
- {
- validSkin = qfalse;
- }
- #endif
-
- // Parse the inventory for the skin
- skin->mInventory = BG_ParseInventory( trap_GPG_FindSubGroup ( subGroup, "Inventory") );
-
- // Link the skin into the skin linked list
- skin->mNext = character->mSkins;
- character->mSkins = skin;
-
- // If the character isnt deathmatch then dont add it to the
- // identity list
- if ( character->mDeathmatch && validSkin)
- {
- // Allocate a new identity
- identity = &bg_identities[bg_identityCount++];
-
- identity->mCharacter = character;
- identity->mSkin = skin;
-
- trap_GPG_FindPairValue ( subGroup, "mp_identity", "", temp );
- if ( !temp[0] )
- {
- identity->mName = trap_VM_LocalStringAlloc ( va("%s/%s", character->mName, skin->mSkin ) );
- }
- else
- {
- identity->mName = trap_VM_LocalStringAlloc ( temp );
- }
-
- // Team name?
- trap_GPG_FindPairValue ( subGroup, "mp_team", "", temp );
- if ( temp[0] )
- {
- identity->mTeam = trap_VM_LocalStringAlloc ( temp );
- }
- else
- {
- identity->mTeam = "";
- }
- }
- }
-
- // Move to the next sub group in the parsers list
- subGroup = trap_GPG_GetNext ( subGroup );
- }
-
- return character->mSkins;
- }
-
- /*
- =================
- BG_ParseModelSounds
-
- Parses the model sounds for the given group and returns a linked
- list with the results
- =================
- */
- TModelSounds *BG_ParseModelSounds( TGPGroup group )
- {
- TModelSounds *top;
- TModelSounds *sounds;
- TGPGroup pairs;
- char temp[1024];
-
- // Convienience
- if ( !group )
- {
- return NULL;
- }
-
- top = NULL;
-
- // Now parse all the skin groups
- pairs = trap_GPG_GetPairs ( group );
- while(pairs)
- {
- // Allocate memory for the sounds
- sounds = (TModelSounds*) trap_VM_LocalAlloc ( sizeof(*sounds) );
- sounds->mNext = top;
- top = sounds;
-
- // Grab the sounds name
- trap_GPV_GetName ( pairs, temp );
- sounds->mName = trap_VM_LocalStringAlloc ( temp );
-
- // Start with no sounds
- sounds->mCount = 0;
-
- // Should be a list
- if ( trap_GPV_IsList ( pairs ) )
- {
- TGPValue list;
-
- // Run through the list
- list = trap_GPV_GetList ( pairs );
- while ( list && sounds->mCount < MAX_MODEL_SOUNDS )
- {
- // Add the sound to the list
- trap_GPV_GetName ( list, temp );
- sounds->mSounds[sounds->mCount++] = trap_VM_LocalStringAlloc ( temp );
-
- list = trap_GPV_GetNext ( list );
- }
- }
-
- // Move to the next sound set in the parsers list
- pairs = trap_GPV_GetNext ( pairs );
- }
-
- return top;
- }
-
- /*
- =================
- BG_ParseItemFile
-
- Parses the item file. The item file contains a list of all of the
- items that can be used as inventory items for a given skin
- =================
- */
- qboolean BG_ParseItemFile ( void )
- {
- TGPGroup *baseGroup, *subGroup;
- TGPValue *pairs;
- TItemTemplate *item;
- TSurfaceList *surf;
- char temp[1024];
- TGenericParser2 ItemFile;
-
- // Create the generic parser so the item file can be parsed
- ItemFile = trap_GP_ParseFile( "ext_data/sof2.item", qtrue, qfalse );
- if ( !ItemFile )
- {
- return qfalse;
- }
-
- baseGroup = trap_GP_GetBaseParseGroup ( ItemFile );
- subGroup = trap_GPG_GetSubGroups ( baseGroup );
- while(subGroup)
- {
- trap_GPG_GetName ( subGroup, temp );
-
- if (Q_stricmp( temp, "item") == 0)
- {
- // Is this item used for deathmatch?
- trap_GPG_FindPairValue ( subGroup, "Deathmatch", "yes", temp );
- if (Q_stricmp( temp, "no") == 0)
- {
- subGroup = trap_GPG_GetNext ( subGroup );
- continue;
- }
-
- // Allocate the item template and link it up to the item list
- item = (TItemTemplate *) trap_VM_LocalAlloc ( sizeof(*item) );
- item->mNext = bg_itemTemplates;
- bg_itemTemplates = item;
-
- // Name of the item
- trap_GPG_FindPairValue ( subGroup, "Name", "", temp );
- item->mName = trap_VM_LocalStringAlloc ( temp );
-
- // Model for the item
- trap_GPG_FindPairValue ( subGroup, "Model", "", temp );
- if ( temp[0] )
- {
- item->mModel = trap_VM_LocalStringAlloc ( temp );
- }
-
- pairs = trap_GPG_GetPairs ( subGroup );
- while(pairs)
- {
- trap_GPV_GetName ( pairs, temp );
-
- // Surface off?
- if ( Q_stricmpn ( temp, "offsurf", 7) == 0)
- {
- // Allocate the surface structure and link it into the list
- surf = (TSurfaceList *) trap_VM_LocalAlloc ( sizeof(*surf) );
- surf->mNext = item->mOffList;
- item->mOffList = surf;
-
- // Name of the surface to turn off
- trap_GPV_GetTopValue ( pairs, temp );
- surf->mName = trap_VM_LocalStringAlloc ( temp );
- }
- // Surface on?
- else if ( Q_stricmpn( temp, "onsurf", 6) == 0)
- {
- // Allocate the surface structure and link it into the list
- surf = (TSurfaceList *) trap_VM_LocalAlloc(sizeof(*surf));
- surf->mNext = item->mOnList;
- item->mOnList = surf;
-
- // Name of the surface to turn off
- trap_GPV_GetTopValue ( pairs, temp );
- surf->mName = trap_VM_LocalStringAlloc ( temp );
- }
-
- // Next pairs
- pairs = trap_GPV_GetNext ( pairs );
- }
- }
-
- // Next group
- subGroup = trap_GPG_GetNext ( subGroup );
- }
-
- trap_GP_Delete(&ItemFile);
-
- return qtrue;
- }
-
- /*
- =================
- BG_FindCharacterTemplate
-
- Finds a character template the matches the given name or NULL if
- a match could not be found
- =================
- */
- TCharacterTemplate *BG_FindCharacterTemplate (const char *name)
- {
- TCharacterTemplate *current;
-
- // Convienience
- if (!name)
- {
- return NULL;
- }
-
- // Linear search through all of the parsed templates
- current = bg_characterTemplates;
- while(current)
- {
- if (Q_stricmp(name, current->mName) == 0)
- {
- return current;
- }
-
- current = current->mNext;
- }
-
- // None found
- return NULL;
- }
-
- /*
- =================
- BG_FindItemTemplate
-
- Finds an item template the matches the given name or NULL if a match
- could not be found
- =================
- */
- TItemTemplate *BG_FindItemTemplate(const char *name)
- {
- TItemTemplate *current;
-
- // Convienience
- if (!name)
- {
- return NULL;
- }
-
- // Linear search through all of the parsed items
- current = bg_itemTemplates;
- while(current)
- {
- if (Q_stricmp(name, current->mName) == 0)
- {
- return current;
- }
-
- current = current->mNext;
- }
-
- return NULL;
- }
-
- /*
- =================
- BG_LinkTemplates
-
- Cross links the various templates
- =================
- */
- static void BG_LinkTemplates(void)
- {
- TCharacterTemplate *current;
- TInventoryTemplate *inv;
- TSkinTemplate *skin;
-
- current = bg_characterTemplates;
- while(current)
- {
- // If this template has a parent then find it and link it up as
- // its parent. Ensure that the parent doesnt link back to itself
- current->mParent = BG_FindCharacterTemplate(current->mParentName);
- if (current->mParent == current)
- {
- current->mParent = NULL;
- }
- // Bring over any parent items
- else if ( current->mParent )
- {
- // No model, bring over the parents.
- if ( !current->mModel )
- {
- current->mModel = current->mParent->mModel;
- }
- }
-
- // Link up all the inventory for this character
- inv = current->mInventory;
- while(inv)
- {
- inv->mItem = BG_FindItemTemplate(inv->mName);
- inv = inv->mNext;
- }
-
- // Link up all the skins for this character
- skin = current->mSkins;
- while(skin)
- {
- // Link up all the inventory items specific to the skins
- inv = skin->mInventory;
- while(inv)
- {
- inv->mItem = BG_FindItemTemplate(inv->mName);
-
- inv = inv->mNext;
- }
-
- skin = skin->mNext;
- }
-
- // Move on to the next character template
- current = current->mNext;
- }
- }
-
- /*
- =================
- BG_ParseNPCFiles
-
- Parses all the the .npc files in the npc directory and
- stores their info into global lists.
- =================
- */
- qboolean BG_ParseNPCFiles ( void )
- {
- int i, numNPCFiles, filelen;
- TGPGroup baseGroup, subGroup;
- TGenericParser2 NPCFile;
- const char *currentParent = 0;
- TCharacterTemplate *newTemplate;
- char fileName[MAX_QPATH];
- char NPCFiles[4096];
- char temp[1024];
- char *fileptr;
-
- // Clear the current list
- bg_characterTemplates = NULL;
-
- // Grab the list of NPC files
- numNPCFiles = trap_FS_GetFileList("NPCs", ".npc", NPCFiles, 4096 );
- if ( !numNPCFiles )
- {
- return qfalse;
- }
-
- // Parse each of the NPC files
- fileptr = NPCFiles;
- for( i=0; i<numNPCFiles; i++, fileptr += filelen+1 )
- {
- // Grab the length so we can skip this file later
- filelen = strlen(fileptr);
-
- Com_sprintf(fileName, sizeof(fileName),"NPCs/%s", fileptr );
-
- // Create the generic parser so the item file can be parsed
- NPCFile = trap_GP_ParseFile( fileName, qtrue, qfalse );
- if ( !NPCFile )
- {
- continue;
- }
-
- baseGroup = trap_GP_GetBaseParseGroup ( NPCFile );
- subGroup = trap_GPG_GetSubGroups ( baseGroup );
-
- while(subGroup)
- {
- trap_GPG_GetName ( subGroup, temp );
-
- // Look for a parent template if this is the group info
- if ( Q_stricmp( temp, "GroupInfo") == 0)
- {
- currentParent = NULL;
-
- // Is there a parent template?
- trap_GPG_FindPairValue ( subGroup, "ParentTemplate", "", temp );
- if ( temp[0] )
- {
- currentParent = trap_VM_LocalStringAlloc ( temp );
- }
- }
- // A new character template
- else if ( Q_stricmp( temp, "CharacterTemplate") == 0)
- {
- // Allocate the new template and link it into the global list.
- newTemplate = (TCharacterTemplate *)trap_VM_LocalAlloc (sizeof(*newTemplate));
- newTemplate->mNext = bg_characterTemplates;
- bg_characterTemplates = newTemplate;
-
- // Exclude from deathmatch?
- trap_GPG_FindPairValue ( subGroup, "DeathMatch", "yes", temp );
- if ( Q_stricmp( temp, "no") == 0)
- {
- newTemplate->mDeathmatch = qfalse;
- }
- else
- {
- newTemplate->mDeathmatch = qtrue;
- }
-
- // Template name
- trap_GPG_FindPairValue ( subGroup, "Name", "", temp );
- if ( temp[0] )
- {
- newTemplate->mName = trap_VM_LocalStringAlloc ( temp );
- }
-
- // Template formal name
- trap_GPG_FindPairValue ( subGroup, "FormalName", "", temp );
- if ( temp[0] )
- {
- newTemplate->mFormalName = trap_VM_LocalStringAlloc ( temp );
- }
-
- // Template model
- trap_GPG_FindPairValue ( subGroup, "Model", "", temp );
- if ( temp[0] )
- {
- newTemplate->mModel = trap_VM_LocalStringAlloc ( temp );
- }
-
- // Use the current parent
- newTemplate->mParentName = currentParent;
-
- // Parse inventory for this character template
- newTemplate->mInventory = BG_ParseInventory( trap_GPG_FindSubGroup( subGroup, "Inventory" ));
-
- // Parse the skins for this character template
- BG_ParseSkins( newTemplate, subGroup);
-
- // Parse the sounds for this character template
- newTemplate->mSounds = BG_ParseModelSounds ( trap_GPG_FindSubGroup ( subGroup, "MPSounds" ) );
- }
-
- // Move to the next group
- subGroup = trap_GPG_GetNext ( subGroup );
- }
-
- trap_GP_Delete(&NPCFile);
- }
-
- // Parse the item file
- BG_ParseItemFile();
-
- // Link up all the templates
- BG_LinkTemplates();
-
- return qtrue;
- }
-
- /*
- =================
- BG_GetModelSoundsGroup
-
- Returns the group of sounds for the given model and sound group combination, if the
- sound group couldnt be found NULL is returned
- =================
- */
- TModelSounds* BG_GetModelSoundsGroup ( const char* Identity, const char* SoundGroup )
- {
- TIdentity *identity;
- TCharacterTemplate *character;
- TModelSounds *sounds;
-
- // Grab the identity in question
- identity = BG_FindIdentity (Identity );
- if ( !identity )
- {
- return NULL;
- }
-
- character = identity->mCharacter;
-
- while ( character )
- {
- // Run through the sounds and look for the match
- sounds = character->mSounds;
- while ( sounds )
- {
- // Match?
- if ( !Q_stricmp ( sounds->mName, SoundGroup ) )
- {
- return sounds;
- }
-
- sounds = sounds->mNext;
- }
-
- character = character->mParent;
- }
-
- // Not found
- return NULL;
- }
-
- /*
- =================
- BG_GetModelSoundCount
-
- Return the number of sounds for the given model
- =================
- */
- int BG_GetModelSoundCount ( const char *Identity, const char *SoundGroup )
- {
- TModelSounds* sounds;
-
- // Grab the sounds
- sounds = BG_GetModelSoundsGroup( Identity, SoundGroup );
- if ( !sounds )
- {
- return 0;
- }
-
- // Return the sound count
- return sounds->mCount;
- }
-
- /*
- =================
- BG_GetModelSound
-
- Returns the model sound for the given sound group and index. If the sound
- could not be found then NULL is returned.
- =================
- */
- const char *BG_GetModelSound ( const char *Identity, const char *SoundGroup, int index )
- {
- TModelSounds *sounds;
-
- // Grab the sounds
- sounds = BG_GetModelSoundsGroup( Identity, SoundGroup );
- if ( !sounds )
- {
- return NULL;
- }
-
- // Invalid index?
- if ( index >= sounds->mCount )
- {
- return "";
- }
-
- // Run through the sounds and look for the match
- return sounds->mSounds[index];
- }
-
- /*
- =================
- BG_FindIdentity
-
- Returns the identity with the given name
- =================
- */
- TIdentity *BG_FindIdentity ( const char *identityName )
- {
- int i;
-
- // Convienience
- if (!identityName)
- {
- return NULL;
- }
-
- // Linear search through all of the parsed identities
- for ( i = 0; i < bg_identityCount; i ++ )
- {
- if (Q_stricmp(identityName, bg_identities[i].mName) == 0)
- {
- return &bg_identities[i];
- }
- }
-
- // None found
- return NULL;
- }
-
- /*
- =================
- BG_FindTeamIdentity
-
- returns the first identity which matches the given team name
- =================
- */
- #define MAX_TEAM_IDENTS 5
- TIdentity* BG_FindTeamIdentity ( const char* teamName, int index )
- {
- TIdentity* idents[MAX_TEAM_IDENTS];
- int count;
- int i;
-
- // Convienience
- if ( !teamName )
- {
- return NULL;
- }
-
- // Linear search through all of the parsed identities
- for ( i = 0, count = 0; i < bg_identityCount && count < MAX_TEAM_IDENTS; i ++ )
- {
- if (Q_stricmp(teamName, bg_identities[i].mTeam) == 0)
- {
- idents[count++] = &bg_identities[i];
- }
- }
-
- if ( !count )
- {
- return NULL;
- }
-
- if ( index != -1 )
- {
- if ( index >= count )
- {
- index = count - 1;
- }
-
- return idents[index];
- }
-
- // None found
- return idents[rand()%count];
- }
-
-
- /*
- =================
- BG_ParseSkin
-
- Reads a skin file into a null terminated list and returns the number found
- =================
- */
- int BG_ParseSkin ( const char* filename, char* pairs, int pairsSize )
- {
- TGenericParser2 skinFile;
- TGPGroup *basegroup;
- TGPGroup *group;
- TGPGroup *sub;
- char name[MAX_QPATH];
- char* end;
- int numPairs;
-
- // Open the skin file
- skinFile = trap_GP_ParseFile( (char*)filename, qtrue, qfalse );
- if ( !skinFile )
- {
- return 0;
- }
-
- numPairs = 0;
- end = pairs;
- *end = 0;
- basegroup = trap_GP_GetBaseParseGroup ( skinFile );
- group = trap_GPG_GetSubGroups ( basegroup );
-
- while(group)
- {
- trap_GPG_GetName ( group, name );
-
- // Parse the material
- if ( Q_stricmp ( name, "material") == 0)
- {
- char matName[MAX_QPATH];
- char shaderName[MAX_QPATH];
-
- trap_GPG_FindPairValue ( group, "name", "", matName );
-
- sub = trap_GPG_FindSubGroup ( group, "group");
- if (sub)
- {
- trap_GPG_FindPairValue ( sub, "shader1", "", shaderName );
- if (!shaderName[0])
- {
- trap_GPG_FindPairValue ( sub, "texture1", "", shaderName );
- }
- }
-
- if (matName[0] && shaderName[0])
- {
- int size;
-
- size = Com_sprintf(end, pairsSize, "%s %s ", matName, shaderName);
- end += size;
- pairsSize -= size;
- numPairs++;
- }
- }
-
- group = trap_GPG_GetNext ( group );
- }
-
- trap_GP_Delete(&skinFile);
-
- return numPairs;
- }
-
- /*
- ==================
- BG_SwingAngles
- ==================
- */
- static void BG_SwingAngles (
- float destination,
- float swingTolerance,
- float clampTolerance,
- float speed,
- float *angle,
- qboolean *swinging,
- int frameTime
- )
- {
- float swing;
- float move;
- float scale;
-
- if ( !*swinging )
- {
- // see if a swing should be started
- swing = AngleSubtract( *angle, destination );
- if ( swing > swingTolerance || swing < -swingTolerance )
- {
- *swinging = qtrue;
- }
- }
-
- if ( !*swinging )
- {
- return;
- }
-
- // modify the speed depending on the delta
- // so it doesn't seem so linear
- swing = AngleSubtract( destination, *angle );
- scale = fabs( swing );
- if ( scale < swingTolerance * 0.5 )
- {
- scale = 0.5;
- }
- else if ( scale < swingTolerance )
- {
- scale = 1.0;
- }
- else
- {
- scale = 2.0;
- }
-
- // swing towards the destination angle
- if ( swing >= 0 )
- {
- move = frameTime * scale * speed;
- if ( move >= swing )
- {
- move = swing;
- *swinging = qfalse;
- }
- *angle = AngleMod( *angle + move );
- }
- else if ( swing < 0 )
- {
- move = frameTime * scale * -speed;
- if ( move <= swing )
- {
- move = swing;
- *swinging = qfalse;
- }
- *angle = AngleMod( *angle + move );
- }
-
- // clamp to no more than tolerance
- swing = AngleSubtract( destination, *angle );
- if ( swing > clampTolerance )
- {
- *angle = AngleMod( destination - (clampTolerance - 1) );
- }
- else if ( swing < -clampTolerance )
- {
- *angle = AngleMod( destination + (clampTolerance - 1) );
- }
- }
-
- /*
- =================
- CG_AddPainTwitch
- =================
- */
- #define PAIN_TWITCH_TIME 200
- static void BG_AddPainTwitch( int painTime, int painDirection, int currentTime, vec3_t torsoAngles ) {
- int t;
- float f;
-
- t = currentTime - painTime;
- if ( t >= PAIN_TWITCH_TIME ) {
- return;
- }
-
- f = 1.0 - (float)t / PAIN_TWITCH_TIME;
-
- if ( painDirection ) {
- torsoAngles[ROLL] += 20 * f;
- } else {
- torsoAngles[ROLL] -= 20 * f;
- }
- }
-
- /*
- =================
- BG_CalculateLeanOffset
- =================
- */
- float BG_CalculateLeanOffset ( int leanTime )
- {
- return ((float)(leanTime - LEAN_TIME) / LEAN_TIME * LEAN_OFFSET);
- }
-
- /*
- =================
- BG_PlayerAngles
- =================
- */
- void BG_PlayerAngles (
-
- vec3_t startAngles,
- vec3_t legs[3],
-
- vec3_t legsAngles, // out
- vec3_t lowerTorsoAngles,
- vec3_t upperTorsoAngles,
- vec3_t headAngles,
-
- int leanOffset,
-
- int painTime,
- int painDirection,
- int currentTime,
-
- animInfo_t* torsoInfo,
- animInfo_t* legsInfo,
-
- int frameTime,
- vec3_t realvelocity,
- qboolean dead,
- float movementDir,
- void* ghoul2
- )
- {
- float dest;
- static int movementOffsets[8] = { 0, 22, 45, -22, 0, 22, -45, -22 };
- float speed;
- int dir;
- vec3_t velocity;
-
- VectorCopy( startAngles, headAngles );
- VectorCopy ( realvelocity, velocity );
- headAngles[YAW] = AngleMod( headAngles[YAW] );
- VectorClear( legsAngles );
- VectorClear( lowerTorsoAngles );
- VectorClear( upperTorsoAngles );
-
- // --------- yaw -------------
-
- // allow yaw to drift a bit
- if ( ( legsInfo->anim & ~ANIM_TOGGLEBIT ) != TORSO_IDLE_PISTOL )
- {
- // if not standing still, always point all in the same direction
- torsoInfo->yawing = qtrue;
- torsoInfo->pitching = qtrue;
- legsInfo->yawing = qtrue;
- }
-
- speed = VectorNormalize( velocity );
-
- // adjust legs for movement dir
- if (dead)
- {
- dir = 0;
- }
- else
- {
- dir = movementDir;
-
- if ( leanOffset && !speed )
- {
- dir = 0;
- }
- }
-
- // legsAngles[YAW] = headAngles[YAW] + 2 * movementOffsets[ dir ];
- // torsoAngles[YAW] = headAngles[YAW] + 2 * movementOffsets[ dir ];
- legsAngles[YAW] = headAngles[YAW] + 2 * movementOffsets[ dir ];
- lowerTorsoAngles[YAW] = headAngles[YAW] + 2 * movementOffsets[ dir ];
-
- // torso
- BG_SwingAngles( lowerTorsoAngles[YAW], 25, 90, 0.3f, &torsoInfo->yawAngle, &torsoInfo->yawing, frameTime );
- BG_SwingAngles( legsAngles[YAW], 40, 90, 0.3f, &legsInfo->yawAngle, &legsInfo->yawing, frameTime );
-
- if ( leanOffset )
- {
- legsAngles[YAW] = headAngles[YAW];
- }
- else
- {
- legsAngles[YAW] = legsInfo->yawAngle;
- }
-
- lowerTorsoAngles[YAW] = Com_Clampf ( -90, 90, AngleDelta (headAngles[YAW], legsAngles[YAW] ) );
- upperTorsoAngles[YAW] = lowerTorsoAngles[YAW] / 2;
- lowerTorsoAngles[YAW] = legsAngles[YAW] + lowerTorsoAngles[YAW] / 2;
-
- headAngles[YAW] -= upperTorsoAngles[YAW];
-
-
- // --------- pitch -------------
-
- // only show a fraction of the pitch angle in the torso
- if ( headAngles[PITCH] > 180 ) {
- dest = (-360 + headAngles[PITCH]) * 0.75;
- } else {
- dest = headAngles[PITCH] * 0.75;
- }
-
- lowerTorsoAngles[PITCH] = dest;
-
- // --------- roll -------------
-
- // lean towards the direction of travel
-
- // Add in leanoffset
- if ( leanOffset )
- {
- lowerTorsoAngles[ROLL] -= ((float)leanOffset * 1.25f);
- lowerTorsoAngles[YAW] -= 1.25f * ((float)leanOffset/LEAN_OFFSET) * dest;
- headAngles[YAW] -= ((float)leanOffset/LEAN_OFFSET) * dest;
- headAngles[ROLL] -= ((float)leanOffset * 1.25f);
- }
- else if ( speed )
- {
- vec3_t axis[3];
- float side;
-
- speed *= 0.025;
-
- AnglesToAxis( legsAngles, axis );
- side = speed * DotProduct( velocity, axis[1] );
- legsAngles[ROLL] -= side;
- }
-
- // pain twitch
- BG_AddPainTwitch( painTime, painDirection, currentTime, lowerTorsoAngles );
-
- // pull the angles back out of the hierarchial chain
- AnglesSubtract( headAngles, lowerTorsoAngles, headAngles );
- AnglesSubtract( lowerTorsoAngles, legsAngles, lowerTorsoAngles );
-
- if ( legs && ghoul2 )
- {
- AnglesToAxis( legsAngles, legs );
-
- // Apply the rotations
- trap_G2API_SetBoneAngles(ghoul2, 0, "upper_lumbar", upperTorsoAngles, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, 0, 0, currentTime);
-
- trap_G2API_SetBoneAngles(ghoul2, 0, "lower_lumbar", lowerTorsoAngles, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, 0, 0, currentTime);
- trap_G2API_SetBoneAngles(ghoul2, 0, "cranium", headAngles, BONE_ANGLES_POSTMULT, POSITIVE_Z, NEGATIVE_Y, POSITIVE_X, 0,0, currentTime);
- }
- }
-
- /*
- ======================
- BG_ParseAnimationFile
-
- Read a configuration file containing animation counts and rates
- models/players/visor/animation.cfg, etc
- ======================
- */
- qboolean BG_ParseAnimationFile ( const char *filename, animation_t* animations )
- {
- const char *text_p;
- int len;
- int i;
- char *token;
- float fps;
- int skip;
- char text[20000];
- fileHandle_t f;
- int animNum;
-
- // load the file
- len = trap_FS_FOpenFile( filename, &f, FS_READ );
- if ( len <= 0 || len >= sizeof( text ) - 1 )
- {
- return qfalse;
- }
-
- trap_FS_Read( text, len, f );
- trap_FS_FCloseFile( f );
-
- // parse the text
- text[len] = 0;
- text_p = text;
- skip = 0;
-
- //initialize anim array so that from 0 to MAX_ANIMATIONS, set default values of 0 1 0 100
- for(i = 0; i < MAX_ANIMATIONS; i++)
- {
- animations[i].firstFrame = 0;
- animations[i].numFrames = 0;
- animations[i].loopFrames = -1;
- animations[i].frameLerp = 100;
- animations[i].initialLerp = 100;
- }
-
- // read information for each frame
- while(1)
- {
- token = COM_Parse( &text_p );
-
- if ( !token || !token[0])
- {
- break;
- }
-
- animNum = GetIDForString(bg_animTable, token);
- if(animNum == -1)
- {
- //#ifndef FINAL_BUILD
- #ifdef _DEBUG
- Com_Printf(S_COLOR_RED"WARNING: Unknown token %s in %s\n", token, filename);
- #endif
- continue;
- }
-
- token = COM_Parse( &text_p );
- if ( !token )
- {
- break;
- }
- animations[animNum].firstFrame = atoi( token );
-
- token = COM_Parse( &text_p );
- if ( !token )
- {
- break;
- }
- animations[animNum].numFrames = atoi( token );
-
- token = COM_Parse( &text_p );
- if ( !token )
- {
- break;
- }
- animations[animNum].loopFrames = atoi( token );
-
- token = COM_Parse( &text_p );
- if ( !token )
- {
- break;
- }
- fps = atof( token );
- if ( fps == 0 )
- {
- fps = 1;//Don't allow divide by zero error
- }
- if ( fps < 0 )
- {//backwards
- animations[animNum].frameLerp = floor(1000.0f / fps);
- }
- else
- {
- animations[animNum].frameLerp = ceil(1000.0f / fps);
- }
-
- animations[animNum].initialLerp = ceil(1000.0f / fabs(fps));
- }
-
- return qtrue;
- }
-
- /*
- ========================
- BG_SetAvailableOutfitting
-
- Set the current availability table
- ========================
- */
- void BG_SetAvailableOutfitting ( const char* available )
- {
- int len;
-
- len = strlen ( available );
- if ( len > WP_NUM_WEAPONS )
- {
- len = WP_NUM_WEAPONS;
- }
-
- // IF the availability has changed force a reload of the outfitting groups
- if ( Q_strncmp ( available, bg_availableOutfitting, min(sizeof(bg_availableOutfitting),len) ) )
- {
- bg_outfittingCount = 0;
- }
-
- // Initialize it to all on.
- memset ( &bg_availableOutfitting[0], '2', sizeof(bg_availableOutfitting) );
- memcpy ( &bg_availableOutfitting[0], available, len );
- }
-
- /*
- ========================
- BG_IsWeaponAvailableForOutfitting
-
- Is the given weapon available for outfitting?
- ========================
- */
- qboolean BG_IsWeaponAvailableForOutfitting ( weapon_t weapon, int level )
- {
- if ( bg_availableOutfitting[0] == -1 )
- {
- return qtrue;
- }
-
- if ( bg_availableOutfitting[weapon-1] - '0' >= level )
- {
- return qtrue;
- }
-
- return qfalse;
- }
-
- /*
- ========================
- BG_DecompressOutfitting
-
- Decompresses the given outfitting string into the outfitting structure
- ========================
- */
- void BG_DecompressOutfitting ( const char* compressed, goutfitting_t* outfitting)
- {
- int group;
- int origitem;
-
- memset ( outfitting->items, 0, sizeof(outfitting->items) );
-
- for ( group = 0; group < OUTFITTING_GROUP_MAX; group ++ )
- {
- int item;
-
- if ( !*compressed )
- {
- item = -1;
- }
- else
- {
- item = ((*compressed++) - 'A');
- }
-
- // Valid item number?
- if ( item < 0 || item >= 10 )
- {
- item = 0;
- }
-
- // Valid slot for the group ?
- if ( bg_outfittingGroups[group][item] == -1 )
- {
- continue;
- }
-
- // Ok to set the item now
- outfitting->items[group] = item;
-
- // No initialized
- if ( bg_availableOutfitting[0] == -1 )
- {
- continue;
- }
-
- // Is it available?
- if ( bg_itemlist[bg_outfittingGroups[group][item]].giType == IT_WEAPON )
- {
- origitem = item;
- while ( !BG_IsWeaponAvailableForOutfitting ( bg_itemlist[bg_outfittingGroups[group][item]].giTag, 2 ) )
- {
- item++;
- if ( bg_outfittingGroups[group][item] == -1 )
- {
- item = 0;
- }
-
- if ( item == origitem )
- {
- //Com_Error ( ERR_FATAL, "ERROR: There must be at least one weapon available in each category" );
- item = -1;
- break;
- }
- }
- }
-
- // Ok to set the item now
- outfitting->items[group] = item;
- }
- }
-
- /*
- ========================
- BG_CompressOutfitting
-
- Compresses the given outfitting structure into the given string
- ========================
- */
- void BG_CompressOutfitting ( goutfitting_t* outfitting, char* compressed, int size )
- {
- int i;
-
- for ( i = 0; i < OUTFITTING_GROUP_MAX && size; i ++, size-- )
- {
- *compressed++ = outfitting->items[i] + 'A';
- }
-
- *compressed = '\0';
- }
-
- /*
- ========================
- BG_FindOutfitting
-
- Finds the real outfitting that matches the given outfitting
- ========================
- */
- int BG_FindOutfitting ( goutfitting_t* outfitting )
- {
- int i;
- int l;
-
- // Loop through all the outfittings linearly
- for ( i = 0; i < bg_outfittingCount; i ++ )
- {
- for ( l = 0; l < OUTFITTING_GROUP_MAX; l ++ )
- {
- if ( bg_outfittings[i].items[l] != outfitting->items[l] )
- {
- break;
- }
- }
-
- // Both iterators at the end signifies a match
- if ( l == OUTFITTING_GROUP_MAX )
- {
- return i;
- }
- }
-
- return -1;
- }
-
- /*
- ========================
- BG_ParseOutfittingTemplate
-
- Parses a single outfitting template
- ========================
- */
- qboolean BG_ParseOutfittingTemplate ( const char* fileName, goutfitting_t* outfitting )
- {
- TGPGroup baseGroup;
- TGPGroup subGroup;
- TGenericParser2 file;
- TGPGroup pairs;
- char temp[MAX_OUTFITTING_NAME];
-
- // Initialize the outfitting
- memset ( outfitting, 0, sizeof(goutfitting_t) );
-
- // Create the generic parser so the item file can be parsed
- file = trap_GP_ParseFile( (char*)fileName, qtrue, qfalse );
- if ( !file )
- {
- return qfalse;
- }
-
- // Start at the top with the "outfitting" group
- baseGroup = trap_GP_GetBaseParseGroup ( file );
- subGroup = trap_GPG_FindSubGroup ( baseGroup, "outfitting" );
- if ( !subGroup )
- {
- trap_GP_Delete(&file);
- return qfalse;
- }
-
- // Get the name of the template
- trap_GPG_FindPairValue ( subGroup, "displayName", fileName, outfitting->name );
-
- // Sub group named "items"
- pairs = trap_GPG_FindPair ( subGroup, "items" );
- if ( pairs )
- {
- TGPValue list;
-
- // Run through the list
- list = trap_GPV_GetList ( pairs );
- while ( list )
- {
- gitem_t* item;
-
- trap_GPV_GetName ( list, temp );
-
- item = BG_FindItem ( temp );
- if ( item )
- {
- int index;
- for ( index=0; bg_outfittingGroups[item->outfittingGroup][index] != -1; index ++ )
- {
- if ( bg_outfittingGroups[item->outfittingGroup][index] == (item - &bg_itemlist[0]) )
- {
- outfitting->items[item->outfittingGroup] = index;
- break;
- }
- }
- }
-
- list = trap_GPV_GetNext ( list );
- }
- }
-
- // Sub group named "weapons"
- pairs = trap_GPG_FindPair ( subGroup, "weapons" );
-
- // Run through the weapons
- if ( pairs )
- {
- TGPValue list;
-
- // Run through the list
- list = trap_GPV_GetList ( pairs );
- while ( list )
- {
- gitem_t* item;
- int i;
-
- trap_GPV_GetName ( list, temp );
-
- // Lookup the weapon number
- for( i = WP_NONE + 1, item=NULL; i < WP_NUM_WEAPONS; i++ )
- {
- if ( Q_stricmp(bg_weaponNames[i], temp ) == 0)
- {
- // translate the weapon index into an item index.
- item = BG_FindWeaponItem ( (weapon_t) i );
- break;
- }
- }
-
- // If the weapon translated into an item ok then drop it
- // in its appropriate slot.
- if ( item )
- {
- int index;
-
- // Make sure outfitting groups that have weapons that are not available
- // do not show up
- if ( !BG_IsWeaponAvailableForOutfitting ( item->giTag, 2 ) )
- {
- trap_GP_Delete(&file);
- return qfalse;
- }
-
- for ( index=0; bg_outfittingGroups[item->outfittingGroup][index] != -1; index ++ )
- {
- if ( bg_outfittingGroups[item->outfittingGroup][index] == (item - &bg_itemlist[0]) )
- {
- outfitting->items[item->outfittingGroup] = index;
- break;
- }
- }
- }
-
- list = trap_GPV_GetNext ( list );
- }
- }
-
- trap_GP_Delete(&file);
-
- return qtrue;
- }
-
- /*
- ========================
- BG_ParseOutfittingTemplates
-
- Parses the available outfitting templates
- ========================
- */
- int BG_ParseOutfittingTemplates ( qboolean force )
- {
- int i;
- int numOutfittingFiles;
- int filelen;
- char fileName[MAX_QPATH];
- char outfittingFiles[4096];
- char *fileptr;
-
- // Dont reload unless forced
- if ( bg_outfittingCount && !force )
- {
- return bg_outfittingCount;
- }
-
- // Clear the current list
- bg_outfittingCount = 1;
- strcpy ( bg_outfittings[0].name, "CUSTOM" );
-
- // Grab the list of NPC files
- numOutfittingFiles = trap_FS_GetFileList("scripts", ".outfitting", outfittingFiles, 4096 );
- if ( !numOutfittingFiles )
- {
- return 0;
- }
-
- // Parse each of the NPC files
- fileptr = outfittingFiles;
- for( i = 0; i < numOutfittingFiles; i++, fileptr += filelen+1 )
- {
- // Grab the length so we can skip this file later
- filelen = strlen(fileptr);
-
- Com_sprintf ( fileName, sizeof(fileName), "scripts/%s", fileptr );
-
- // Parse the outfitting template
- if ( BG_ParseOutfittingTemplate ( fileName, &bg_outfittings[bg_outfittingCount] ) )
- {
- bg_outfittingCount++;
- }
- }
-
- return bg_outfittingCount;
- }
-
-
-